<?php

namespace DreamCat\FrameCore\Factory\Impl\Container;

use DreamCat\Array2Class\Array2ClassConverter;
use DreamCat\Array2Class\Array2ClassInterface;
use DreamCat\Container\Container;
use DreamCat\FrameCore\Factory\Impl\ActionParam\DefaultActionParamFactory;
use DreamCat\FrameCore\Factory\Impl\AnnotationDealer\ConfigerDealer;
use DreamCat\FrameCore\Factory\Impl\AnnotationDealer\RootDirPath;
use DreamCat\FrameCore\Factory\Impl\Controller\DefaultControllerFactory;
use DreamCat\FrameCore\Factory\Impl\Dispatchers\DefaultDispatcherFactory;
use DreamCat\FrameCore\Factory\Impl\LoggerFactory\DefaultLoggerFactory;
use DreamCat\FrameCore\Factory\Impl\ServerRequest\DefaultServerRequestFactory;
use DreamCat\FrameCore\Helper\ConfigHelper\BeansConfig;
use DreamCat\FrameCore\HttpHandle\DefaultErrorHandle;
use DreamCat\FrameCore\HttpHandle\DefaultHttpRequestProcess;
use DreamCat\FrameCore\Share\Container\RegeditBean;
use DreamCat\FrameInterface\ConfigReader;
use DreamCat\FrameInterface\Controller\ActionParamFactory;
use DreamCat\FrameInterface\Factory\ContainerFactory;
use DreamCat\FrameInterface\Factory\ControllerFactory;
use DreamCat\FrameInterface\HttpHandle\ErrorHandle;
use DreamCat\FrameInterface\HttpHandle\HttpRequestProcess;
use FastRoute\Dispatcher;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Zend\HttpHandlerRunner\Emitter\EmitterInterface;
use Zend\HttpHandlerRunner\Emitter\SapiEmitter;

/**
 * 默认的容器工厂
 * @author vijay
 */
class DefaultContainerFactory implements ContainerFactory
{
    use RegeditBean;
    /**
     * 根据配置创建容器
     * @param ConfigReader $configReader 配置读取器
     * @return ContainerInterface
     */
    public function create(ConfigReader $configReader): ContainerInterface
    {
        $container = new Container();

        # 保存配置读取器
        $container->regeditInstance("configReader", $configReader);
        $container->regeditInstance(get_class($configReader), $configReader);
        $container->regeditInstance(ConfigReader::class, $configReader);

        # 添加注解处理器
        $container->regeditAnnotation("Config", new ConfigerDealer($configReader));
        $container->regeditAnnotation("RootPath", new RootDirPath($configReader->getRootDir()));

        # 从配置中读取bean配置
        $container = $this->importConfig($configReader->get("beans", []), $container);
        return $container;
    }

    /**
     * 导入bean配置文件
     * @param array $config 配置文件
     * @param Container $container 容器对象
     * @return Container
     */
    protected function importConfig(array $config, Container $container): Container
    {
        $config = $this->importDefault($config);
        foreach ($config as $id => $beanConfig) {
            $container = $this->regeditBeanIntoContainer($id, $beanConfig, $container);
        }
        return $container;
    }

    /**
     * 导入默认bean配置
     * @param array $config
     * @return array
     */
    protected function importDefault(array $config): array
    {
        # 补充默认容器配置
        $defaultBeans = [
            HttpRequestProcess::class => BeansConfig::byClass(DefaultHttpRequestProcess::class),
            EmitterInterface::class => BeansConfig::byClass(SapiEmitter::class),
            ErrorHandle::class => BeansConfig::byClass(DefaultErrorHandle::class),
            LoggerInterface::class => BeansConfig::factory(DefaultLoggerFactory::class),
            ControllerFactory::class => BeansConfig::byClass(DefaultControllerFactory::class),
            Dispatcher::class => BeansConfig::factory(DefaultDispatcherFactory::class),
            ServerRequestInterface::class => BeansConfig::factory(DefaultServerRequestFactory::class),
            ActionParamFactory::class => BeansConfig::byClass(DefaultActionParamFactory::class),
            Array2ClassInterface::class => BeansConfig::byClass(Array2ClassConverter::class),
        ];
        foreach ($defaultBeans as $id => $beanConfig) {
            if (!isset($config[$id])) {
                $config[$id] = $beanConfig;
            }
        }
        return $config;
    }
}

# end of file
